﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using StockFinder.Model;
using StockFinder.Model.Constants;

namespace StockFinder.Indicators.Day.ClosePrice
{
    public class ExponentialMovingAverageTrueRangeClosePriceDayIndicator : BaseDayIndicator
    {
        public ExponentialMovingAverageTrueRangeClosePriceDayIndicator(int lookbackPeriod, string indicatorName) : base(lookbackPeriod, indicatorName)
        {
        }

        public override void ApplyIndicator(List<DailyPrice> prices)
        {
            if (!Initialize(prices)) return;
            
            decimal averageTrueRange = 0M;
            decimal cummulativeTrueRange = 0M;
            var orderedPrices = prices.OrderBy(p => p.PriceDate);                
            DailyPrice currentPrice, previousPrice;

            var pricesArray = orderedPrices.ToArray();
            var pricesArrayCount = pricesArray.Count();            

            //array
            for (int i = 0; i < pricesArrayCount; i++)
            {
                currentPrice = pricesArray[i];

                var highLow = currentPrice.AdjustedHigh - currentPrice.AdjustedLow;

                decimal trueRange = 0M;
                if (i == 0)
                {
                    trueRange = highLow;
                }
                else
                {
                    previousPrice = pricesArray[i - 1];

                    var highPrevClose = Math.Abs(currentPrice.AdjustedHigh - previousPrice.AdjustedClose);

                    var lowPrevClose = Math.Abs(currentPrice.AdjustedLow - previousPrice.AdjustedClose);

                    trueRange = Math.Max(highLow, Math.Max(highPrevClose, lowPrevClose));
                }

                cummulativeTrueRange += trueRange;

                if (i == (LookbackPeriod - 1))
                {
                    averageTrueRange = (cummulativeTrueRange / LookbackPeriod);

                    currentPrice.DayIndicators[IndicatorName] = Math.Round(averageTrueRange, 2);                        
                }

                if (i > (LookbackPeriod - 1))
                {
                    averageTrueRange = ((averageTrueRange * (LookbackPeriod - 1)) + trueRange) / LookbackPeriod;

                    currentPrice.DayIndicators[IndicatorName] = Math.Round(averageTrueRange, 5);                        
                }                    
            }            
        }

        #region Common Indicators
        public static readonly ExponentialMovingAverageTrueRangeClosePriceDayIndicator _14 = new ExponentialMovingAverageTrueRangeClosePriceDayIndicator(14, DayIndicatorNames.CLOSE_EMATR14);
        public static readonly ExponentialMovingAverageTrueRangeClosePriceDayIndicator _20 = new ExponentialMovingAverageTrueRangeClosePriceDayIndicator(20, DayIndicatorNames.CLOSE_EMATR20);
        #endregion
    }
}
